package com.common.fileupload.upload.impl;

import com.common.fileupload.config.S3UploaderConfig;
import com.common.fileupload.domain.FileModel;
import com.common.fileupload.upload.S3FileUploader;
import com.google.common.collect.ImmutableMap;
import io.minio.*;
import io.minio.errors.MinioException;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Slf4j
@ConditionalOnProperty(name = "upload.impl", havingValue = "minio")
public class MinIOUploader implements S3FileUploader<MinioClient> {



    @Autowired
    private S3UploaderConfig uploadConfig;



    @Override
    public MinioClient getClient() {
        return uploadConfig.getClient(MinioClient.class,
                config -> MinioClient.builder()
                        .endpoint(config.getEndPoint())
                        .credentials(config.getAccessKey(), config.getSecretKey())
                        .build());
    }

    @Override
    public FileModel put(InputStream inputStream, String prefix, String fileName, String contentType, Long fileSize) {
        String fileId = UUID.randomUUID().toString();
        String suffix = fileName.substring(fileName.lastIndexOf("."));
//        String objectName = fileName;
        String objectName = fileId + suffix;
        if (StringUtils.isNotBlank(prefix)) {
            objectName = prefix + "/" + objectName;
        }
        try {
            getClient().putObject(PutObjectArgs.builder()
                    .bucket(uploadConfig.getBucketName())
                    .object(objectName)
                    .stream(inputStream, fileSize, -1)
                    .contentType(contentType)
                    .userMetadata(ImmutableMap.of(
                            FILE_ID_KEY, fileId,
                            FILE_NAME_KEY, fileName,
                            FILE_SUFFIX_KEY, suffix,
                            CONTENT_TYPE_KEY, contentType))
                    .build());

            return new FileModel()
                    .setId(fileId)
                    .setOriginName(fileName)
                    .setObjectName(objectName)
                    .setSuffix(suffix)
                    .setContentType(contentType)
                    .setSize(fileSize)
                    .setPath(objectName)
                    .setPrefix(uploadConfig.getPrefix())
                    .setUrl(uploadConfig.getUrl(objectName))
                    .setCrAt(new Date());
        } catch (MinioException | GeneralSecurityException | IOException e) {
            log.error("上传图片错误. e=", e);
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * 获取文件信息
     *
     * @param filePath
     * @return
     * @throws Exception
     */
    @Override
    public FileModel peek(String filePath) {
        try {
            StatObjectResponse stat = getClient().statObject(StatObjectArgs.builder()
                    .bucket(uploadConfig.getBucketName())
                    .object(filePath)
                    .build());
            long size = stat.size();
            ZonedDateTime crAt = stat.lastModified();
            String contentType = stat.contentType();
            String fileId = stat.userMetadata().get(FILE_ID_KEY);
            String fileName = stat.userMetadata().get(FILE_NAME_KEY);
            String suffix = fileName.substring(fileName.lastIndexOf("."));
            return new FileModel()
                    .setId(fileId)
                    .setOriginName(fileName)
                    .setObjectName(filePath)
                    .setSuffix(suffix)
                    .setContentType(contentType)
                    .setSize(size)
                    .setPath(filePath)
                    .setPrefix(uploadConfig.getPrefix())
                    .setUrl(uploadConfig.getUrl(filePath))
                    .setCrAt(Date.from(crAt.toInstant()));
        } catch (MinioException | GeneralSecurityException | IOException e) {
            log.error("图片详情错误. e=", e);
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * 下载文件
     */
    @Override
    public InputStream get(String filePath) {
        GetObjectArgs args = GetObjectArgs.builder()
                .bucket(uploadConfig.getBucketName())
                .object(filePath)
                .build();
        try {
            return getClient().getObject(args);
        } catch (MinioException | GeneralSecurityException | IOException e) {
            log.error("图片详情错误. e=", e);
            throw new IllegalArgumentException(e);
        }
    }

    @Override
    public List<FileModel> list(String prefix) {
        Iterable<Result<Item>> results = getClient().listObjects(ListObjectsArgs.builder()
                .bucket(uploadConfig.getBucketName())
                .prefix(prefix + "/")
                .build());

        List<FileModel> list = new ArrayList<>();
        results.forEach(r -> {
            try {
                Item item = r.get();
                if (item.size() > 0) {
                    FileModel fileModel = new FileModel()
                            .setObjectName(item.objectName())
                            .setSize(item.size())
                            .setPath(item.objectName())
                            .setPrefix(uploadConfig.getPrefix())
                            .setUrl(uploadConfig.getUrl(item.objectName()))
                            .setCrAt(Date.from(item.lastModified().toInstant()));
                    if (item.userMetadata() != null) {
                        String fileId = item.userMetadata().get(FILE_ID_KEY);
                        String fileName = item.userMetadata().get(FILE_NAME_KEY);
                        String contentType = item.userMetadata().get(CONTENT_TYPE_KEY);
                        String suffix = fileName.substring(fileName.lastIndexOf("."));
                        fileModel.setId(fileId)
                                .setOriginName(fileName)
                                .setSuffix(suffix)
                                .setContentType(contentType);
                    }
                    list.add(fileModel);
                }
            } catch (Exception e) {
                //do nothing
            }
        });
        return list;
    }
}
